﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using Ext.Net;
using Ext.Net.Utilities;
using KamLib.Controls;
using Newtonsoft.Json.Linq;

namespace KamLib
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    [ScriptService]
    public class UilService : WebService
    {

        #region Tools

        public readonly XControlResponse Response = new XControlResponse();
        public readonly UilContext LogicContext = new UilContext();

        protected override void Dispose(bool disposing)
        {
            LogicContext.Dispose();
            base.Dispose(disposing);
        }

        public UilController NewController(string lid)
        {
            var ctrl = LogicContext.GetController(lid);
            ctrl.VirtualPath = GetVirtualDirectory();
            return ctrl;
        }
        public UilController NewController(UiKey key)
        {
            return NewController(key.LID);
        }

        protected string GetVirtualDirectory()
        {
            return VirtualPathUtility.GetDirectory(
                Context.Request.Url.AbsolutePath.LeftOfRightmostOf('/').TrimStart('~')
            );
        }

        #endregion


        #region Grid

        public class ScriptPaging<T> : Paging<T>
        {
            public string Script { get; set; }

            public ScriptPaging(IEnumerable<T> data, int totalRecords, string script)
                : base(data, totalRecords)
            {
                Script = script;
            }
        }

        [WebMethod]
        public virtual ScriptPaging<object> ListSelect(string key, int? start, int? limit, string group, string sort, string dir, string gridfilters, string monitorId)
        {
            try
            {
                UiKey okey = key;
                var logic = NewController(okey).GetList(okey);
                logic.Key = okey;

                var sortDir = dir.IsNotEmpty() ? (SortDirection)Enum.Parse(typeof(SortDirection), dir, true) : SortDirection.Default;

                var e = new WhereArgs(LogicContext)
                {
                    Start = start ?? 0,
                    Limit = limit ?? logic.PageSize,
                    SortFields = 
                    { 
                        new WhereArgSortField 
                        { 
                            Name= sort.IfNull(logic.SortField).IfNull(logic.KeyField) ,
                            Dir = sortDir != SortDirection.Default ? sortDir : logic.SortDir,
                        }
                    },
                    TotalExpected = true,
                    Filters = WhereArgs.NewFilters(gridfilters),
                };

                if (group.isfull())
                    e.SortFields.Insert(0, group);

                var list = logic.Select(e);

                var script = logic.Script;
                if (monitorId.IsNotEmpty())
                {
                    var mc = Response.Modify<MonitorControl>(monitorId);
                    mc.AddState(logic.Errors);
                }

                LogicContext.Notifications.Show();
                script += Response.ToScript();

                return new ScriptPaging<object>(list, e.Total, script);
            }
            catch (Exception ex)
            {
                throw new Exception(key + "<br>" + ex.FullMessage().Replace("\r\n", "<br>"), ex);
            }
        }

        [WebMethod]
        public virtual DirectResponse RowRefresh(string key)
        {
            try
            {
                UiKey okey = key;
                var logic = NewController(okey).GetList("List", okey);
                Response.Params.AddRaw("resync", logic.Resync(0).Select(a => new { key = a.Key, d = a.Value }).ToList());
                LogicContext.Notifications.Show();
                return Response;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.FullMessage().Replace("\r\n", "<br>"), ex);
            }
        }

        #endregion

        #region Form

        public DirectResponse ChangeForm(UiKey key, Action<FormLogic> change)
        {
            try
            {
                var frm = NewController(key).GetForm(key);
                if (frm == null)
                    throw new Exception("Can't find form by key " + key);
                frm.Response = Response;
                using (frm)
                {
                    change(frm);
                }
                //Response.SafeExecScript = true;
                LogicContext.Notifications.Show();
                return Response;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.FullMessage()/*.Replace("\r\n", "<br>")*/, ex);
            }
        }

        public DirectResponse ModifyEntity(UiKey key)
        {
            //using (LogicContext.Log = new LogWriter(Context.Request.MapPath("~/log01.txt")) { ShowMilliseconds = true })
            //{
            //var log = LogicContext.Log;
            //try
            //{
            //log += "ModifyEntity";
            return ChangeForm(key, logic =>
            {
                //log += "change()";
                logic.CreateControl();
                //log &= "CreateControl";
                var values = logic.GetData();
                if (values == null) return;
                logic.SetValues(values);
                //log &= "SetValues";
                Response.Params.AddRaw("key", logic.Key);
                //log &= "AddRaw";
                //log--;
            });
            //    }
            //    finally
            //    {
            //        log--;
            //    }
            //}
        }

        [WebMethod]
        public DirectResponse AddEntity(string key)
        {
            return ModifyEntity(key);
        }

        [WebMethod]
        public virtual DirectResponse EditEntity(string key)
        {
            return ModifyEntity(key);
        }

        [WebMethod]
        public DirectResponse GetFormData(string key)
        {
            return ChangeForm(key, logic => Response.Params.AddRaw("values", logic.GetData()));
        }

        [WebMethod]
        public DirectResponse SaveFormData(string key, string values, bool beenClosed)
        {
            return ChangeForm(key, logic =>
            {
                logic.JValues = values;
                logic.SaveData();
                logic.ReloadDependentStores();

                Response.Params.AddRaw("key", logic.Key.ToJson());

                Response.Params.AddRaw("resync", (
                    from a in logic.Resync(beenClosed ? UilResyncMode.Close : 0)
                    select new { key = a.Key, d = a.Value }
                ).ToList());
            });
        }

        [WebMethod]
        public DirectResponse DeleteEntity(string key)
        {
            return ChangeForm(key, logic =>
            {
                logic.DeleteData();
                Response.Params.AddRaw("resync", (
                    from a in logic.Resync(UilResyncMode.Delete)
                    select new { key = a.Key, d = a.Value }
                ).ToList());
            });
        }

        #endregion

    }

}